/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including but not limited to the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to provide persons with access to the Software
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGE OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

interface VelocityValue {
  velocityX: number,
  velocityY: number,
  velocity: number,
}

import { DirectionParam } from '../../src/types/pointerGestureManager/index';
export function getSwipeDirection(deltaX: number, deltaY: number, directionParam: DirectionParam): boolean {
  const angle = (Math.atan2(deltaY, deltaX) * (180 / Math.PI) + 360) % 360;
  const isAnd = directionParam.includes('&');
  const isOr = directionParam.includes('|');
  const isNone = directionParam.includes('None');
  // 与计算
  if (isAnd && !isNone) {
    return isAndTrigger(directionParam, angle);
  }
  // 或计算
  if (isOr) {
    return isOrTrigger(directionParam, angle);
  }
  // 单独方向匹配
  return individualDirection(angle, directionParam);
}

function isAndTrigger(directionParam: DirectionParam, angle: number): boolean {
  const getIntervals = getPandomIntervals(directionParam, '&');
  const interSection = intersectAllIntervals(getIntervals[0]);
  if (getIntervals[1].length > 0 && getIntervals[2].length > 0) {
    return false;
  }
  if (getIntervals[1].length > 0) {
    const interSectionA = intersectAllIntervals([...interSection, getIntervals[1][0]]);
    const interSectionB = intersectAllIntervals([...interSection, getIntervals[1][1]]);
    const isInterSectionA = isNumberInIntervals(angle, interSectionA);
    const isInterSectionB = isNumberInIntervals(angle, interSectionB);
    return (isInterSectionA || isInterSectionB);
  }
  if (getIntervals[2].length > 0) {
    const interSectionA = intersectAllIntervals([...interSection, getIntervals[2][0]]);
    const interSectionB = intersectAllIntervals([...interSection, getIntervals[2][1]]);
    const isInterSectionA = isNumberInIntervals(angle, interSectionA);
    const isInterSectionB = isNumberInIntervals(angle, interSectionB);
    return (isInterSectionA || isInterSectionB);
  }
  const isInterSection = isNumberInIntervals(angle, interSection);
  return isInterSection;
}

function isOrTrigger(directionParam: DirectionParam, angle: number): boolean {
  const getIntervals = getPandomIntervals(directionParam, '|');
  const union = calculateUnion(getIntervals[0]);
  if (getIntervals[1].length > 0 && getIntervals[2].length > 0) {
    return true;
  }
  if (getIntervals[1].length > 0) {
    const interSection = calculateUnion([...union, ...getIntervals[1]]);
    const isInterSection = isNumberInIntervals(angle, interSection);
    return isInterSection;
  }
  if (getIntervals[2].length > 0) {
    const interSection = calculateUnion([...union, ...getIntervals[2]]);
    const isInterSection = isNumberInIntervals(angle, interSection);
    return isInterSection;
  }
  const isInterSection = isNumberInIntervals(angle, union);
  return isInterSection;
}

//对传入的方向划分区间
function getPandomIntervals(directionParam: string, isAnd: string): number[][][] {
  const directions = directionParam.split(isAnd);
  const selected: number[][] = [];
  const selectedA: number[][] = [];
  const selectedB: number[][] = [];
  directions.forEach(item => {
    switch (item) {
      case 'All':
        selected.push([0, 360]);
        break;
      case 'Horizontal':
        selectedA.push([135, 225], [315, 45]);
        break;
      case 'Vertical':
        selectedB.push([45, 135], [225, 315]);
        break;
      case 'Left':
        selected.push([90, 270]);
        break;
      case 'Right':
        selected.push([270, 90]);
        break;
      case 'Up':
        selected.push([180, 360]);
        break;
      case 'Down':
        selected.push([0, 180]);
        break;
      default:
    }
  });
  return [selected, selectedA, selectedB];
}
// 处理区间循环
function normalizeInterval(interval: number[]): number[][] {
  const [start, end] = interval;
  if (start <= end) {
    return [[start, end]];
  } else {
    return [[start, 360], [0, end]];
  }
}

function intersectIntervals(intervalA: number[][], intervalB: number[][]): number[][] {
  const result: number[][] = [];
  for (const intA of intervalA) {
    for (const intB of intervalB) {
      const start = Math.max(intA[0], intB[0]);
      const end = Math.min(intA[1], intB[1]);
      if (start <= end) {
        result.push([start, end]);
      }
    }
  }
  return result;
}

function intersectAllIntervals(intervals: number[][]): number[][] {
  if (intervals.length === 0) {
    return [];
  }
  let currentIntersection = normalizeInterval(intervals[0]);
  for (let i = 1; i < intervals.length; i++) {
    const nextInterval = normalizeInterval(intervals[i]);
    currentIntersection = intersectIntervals(currentIntersection, nextInterval);
    if (currentIntersection.length === 0) {
      break;
    }
  }
  return currentIntersection;
}

// 计算并集
function calculateUnion(intervals: number[][]): number[][] {
  if (intervals.length === 0) {
    return [];
  }
  const expandedIntervals = [];
  for (let i = 0; i < intervals.length; i++) {
    expandedIntervals.push(...normalizeInterval(intervals[i]));
  }
  const sorted = [...expandedIntervals].sort();
  const merged = [sorted[0]];
  for (let i = 1; i < sorted.length; i++) {
    const last = merged[merged.length - 1];
    const current = sorted[i];
    if (current[0] <= last[1]) {
      last[1] = Math.max(last[1], current[1]);
    } else {
      merged.push(current);
    }
  }
  return merged;
}
// 判断是否在区间集合中
function isNumberInIntervals(num: number, intervals: number[][]): boolean {
  // 处理环形区间（0-90和270-360视为连续）
  for (let interval of intervals) {
    const [start, end] = interval;
    if (start <= end && num >= start && num <= end) {
      return true;
    }
    if (start > end && (num >= start || num <= end)) {
      return true;
    }
  }
  return false;
}

function individualDirection(angle: number, directionParam: string): boolean {
  switch (directionParam) {
    case 'All':
      return true;
    case 'Horizontal':
      return ((angle > 315 && angle <= 360) || (angle > 0 && angle <= 45) || (angle > 135 && angle < 225));
    case 'Vertical':
      return (angle > 225 && angle <= 315) || (angle > 45 && angle <= 135);
    case 'Left':
      return (angle > 90 && angle <= 270);
    case 'Right':
      return ((angle > 270 && angle <= 360) || (angle > 0 && angle <= 90));
    case 'Up':
      return (angle > 180 && angle <= 360);
    case 'Down':
      return (angle > 0 && angle <= 180);
    default:
  }
  return false;
}

export function getAngle(x1: number, y1: number, x2: number, y2: number): number {
  const rad = Math.atan2(y2 - y1, x2 - x1);
  return rad * (180 / Math.PI);
}

export function getPointersCenter(touchs: PointerEvent[]): { x: number; y: number } {
  if (touchs.length === 0) {
    return { x: 0, y: 0 };
  }
  if (touchs.length === 1) {
    return {
      x: touchs[0].clientX,
      y: touchs[0].clientY,
    };
  }
  const p1 = touchs[0];
  const p2 = touchs[1];
  return {
    x: (p1.clientX + p2.clientX) / 2,
    y: (p1.clientY + p2.clientY) / 2,
  };
}

export function getPointersDistance(touchs: PointerEvent[]): number {
  if (touchs.length < 2) {
    return 0;
  }
  const p1 = touchs[0];
  const p2 = touchs[1];
  return Math.sqrt(
    Math.pow(p2.clientX - p1.clientX, 2) +
    Math.pow(p2.clientY - p1.clientY, 2)
  );
}

export function getVelocityValue(startVelocityX: number, startVelocityY: number, endVelocityX: number, endVelocityY: number, lastTime: number): VelocityValue {
  const now = Date.now();
  const deltaTime = now - lastTime;
  const deltaX = endVelocityX - startVelocityX;
  const deltaY = endVelocityY - startVelocityY;
  const actualDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
  const actualSpeed = actualDistance / deltaTime;
  const velocityX = deltaX / deltaTime;
  const velocityY = deltaY / deltaTime;
  return {
    velocityX: velocityX,
    velocityY: velocityY,
    velocity: actualSpeed,
  };
}
